/***************************************************************************
 *   Copyright (C) 2009 by Marian Skvarek   *
 *   skvarek.marian@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "CNoteGroup.h"
#include "CNoteGroupView.h"
#include "CBar.h"
#include "CNote.h"
#include "limits.h"

namespace easyscore
{
    namespace core
    {

        CNoteGroup::CNoteGroup()
        {
            mTemporaryNote = 0;
            mView = 0;

            initialize();
        }

        void CNoteGroup::initialize()
        {

        }

        void CNoteGroup::clear()
        {
            foreach (CNote *note, mNotes)
                delete note;
            mNotes.clear();

            destroyView();
        }


        CNoteGroup::~CNoteGroup()
        {
            clear();
        }

        CNote* CNoteGroup::insertNote(int position)
        {

            CNote *newNote = new CNote( position );
            newNote->setParentNoteGroup(this);
            newNote->initialize();
            mNotes.append(newNote);
            updateView();

            return newNote;
        }

        void CNoteGroup::removeNote(CNote *note)
        {
            mNotes.removeOne(note);
            delete note;

            updateView();
        }

        CNote *CNoteGroup::getHighestNote()
        {
            int maxPosition = 0;
            CNote *result = 0;
            foreach (CNote *note, mNotes)
            {
                if(note->getPosition() >= maxPosition)
                {
                    maxPosition = note->getPosition();
                    result = note;
                }
            }

            return result;
        }

        CNote *CNoteGroup::getLowestNote()
        {
            int minPosition = INT_MAX;
            CNote *result = 0;
            foreach (CNote *note, mNotes)
            {
                if(note->getPosition() <= minPosition)
                {
                    minPosition = note->getPosition();
                    result = note;
                }
            }

            return result;
        }

        CNote *CNoteGroup::getByPosition(NOTE_POSITION pos)
        {
            foreach (CNote *note, mNotes)
            {
                if((note != mTemporaryNote) && (note->getPosition() == pos))
                {
                    return note;
                }
            }

            return 0;
        }

        void CNoteGroup::insertTemporaryNote(int position)
        {
            deleteTemporaryNote();

            mTemporaryNote = insertNote(position);
        }

        void CNoteGroup::deleteTemporaryNote()
        {
            if(mTemporaryNote)
            {
                removeNote(mTemporaryNote);
                mTemporaryNote = 0;
            }
        }

        void CNoteGroup::confirmTempraryNote()
        {
            if(mTemporaryNote)
            {

                if(!getByPosition(mTemporaryNote->getPosition()))
                {
                    mTemporaryNote = 0;
                    mParentBar->confirmTemporaryNoteGroup();
                }
            }
        }

        void CNoteGroup::setTablature(FRETBOARD_POSITION position)
        {
            mTab.initialize();

            QLinkedList<CNote *> notes = mNotes;
            QLinkedList<CNote *> sortedNotes;

            while(!notes.empty())
            {
                int maxPosition = 0;
                CNote *result = 0;
                foreach (CNote *note, notes)
                {
                    if(note->getPosition() >= maxPosition)
                    {
                        maxPosition = note->getPosition();
                        result = note;
                    }
                }

                sortedNotes.append(result);
                notes.removeOne(result);
            }

            NOTE_PITCH currentString = PITCHE5;
            foreach(CNote *currentNote,sortedNotes)
            {
                NOTE_PITCH currPitch = currentNote->getAbsoluteNotePitch();

                bool found;
                do
                {
                    NOTE_PITCH diff = currPitch - (currentString + position);
                    found = (diff  < POSITION_RANGE)
                            && (diff >= 0)
                            && (mTab.get(fromPitch(currentString)) == POSITION_NONE);
                    if(found)
                        mTab.set(fromPitch(currentString),currPitch - currentString);
                    else
                        currentString = nextString(currentString);


                }while( (!found)  && (currentString >= STRINGE3) );

            }
        }

        void CNoteGroup::createView()
        {
            destroyView();

            mView = new CNoteGroupView(this);
        }

        void CNoteGroup::destroyView()
        {
            if(hasView())
            {
                delete mView;
                mView = 0;
            }
        }
	
        //Protected methods
        void CNoteGroup::updatePositionList()
        {
            mPositionList.ones();

            foreach(CNote *note,mNotes)
            {

                mPositionList.andIt(note->getPositionList());
            }
        }

        NOTE_PITCH CNoteGroup::nextString(NOTE_PITCH string)
        {
            if(string == PITCHH4)
                return string -4;
            else
                return string -5;
        }

        STRING_NAME CNoteGroup::fromPitch(NOTE_PITCH stringPitch)
        {
            switch(stringPitch)
            {
            case PITCHE5: return STRINGE5;
            case PITCHH4: return STRINGH;
            case PITCHG4: return STRINGG;
            case PITCHD4: return STRINGD;
            case PITCHA3: return STRINGA;
            default: return STRINGE3;
            }
        }

        void CNoteGroup::updateView()
        {
            if( hasView() )
                mView->update();
        }

    }
}
